package com.wqiuqiu.gulimall.cart.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.wqiuqiu.common.R;
import com.wqiuqiu.gulimall.cart.feign.ProductFeignService;
import com.wqiuqiu.gulimall.cart.interceptor.CartInterceptor;
import com.wqiuqiu.gulimall.cart.service.CartService;
import com.wqiuqiu.gulimall.cart.vo.*;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;


import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Service
public class CartServiceImpl implements CartService {

    public static final String CART_PREFIX = "gulimall:cart:";


    @Autowired
    ProductFeignService productFeignService;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    ThreadPoolExecutor executor;

    @Override
    public CartItemVo addCart(Long skuId, Integer num) throws ExecutionException, InterruptedException {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        String str = (String) cartOps.get(skuId.toString());
        CartItemVo itemVo;
        if (StringUtils.isEmpty(str)) {
            //需要新增 去商品服务查skuinfo 以异步方式执行
            itemVo = new CartItemVo();
            CompletableFuture<Void> getSkuInfo = CompletableFuture.runAsync(() -> {
                R info = productFeignService.info(skuId);
                if (info.getCode() == 0) {
                    SkuInfoVo skuInfo = info.getData(new TypeReference<SkuInfoVo>() {
                    });
                    itemVo.setSkuId(skuId);
                    itemVo.setCount(num);
                    itemVo.setPrice(skuInfo.getPrice());
                    itemVo.setTotalPrice(itemVo.getPrice().multiply(new BigDecimal(itemVo.getCount())));
                    //查销售属性
                    itemVo.setSkuImage(skuInfo.getSkuDefaultImg());
                    itemVo.setSkuName(skuInfo.getSkuTitle());
                }
            }, executor);
            CompletableFuture<Void> getSaleAttr = CompletableFuture.runAsync(() -> {
                List<String> skuSaleAttrValues = productFeignService.getSkuSaleAttrValues(skuId);
                itemVo.setAttrs(skuSaleAttrValues);
            }, executor);

            CompletableFuture.allOf(getSkuInfo, getSaleAttr).get();

            String string = JSON.toJSONString(itemVo);
            cartOps.put(skuId.toString(), string);

        } else {
            itemVo = JSON.parseObject(str, CartItemVo.class);
            itemVo.setCount(itemVo.getCount() + num);
            itemVo.setTotalPrice(itemVo.getPrice().multiply(new BigDecimal(itemVo.getCount())));
            String string = JSON.toJSONString(itemVo);
            cartOps.put(skuId.toString(), string);
        }
        return itemVo;
    }



    /**
     * 获取购物车项根据skuId
     *
     * @param skuId
     * @return
     */
    @Override
    public CartItemVo getCart(Long skuId) {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        String str = (String) cartOps.get(skuId.toString());
        CartItemVo itemVo = new CartItemVo();
        if (StringUtils.isNotEmpty(str)) {
            itemVo = JSON.parseObject(str, CartItemVo.class);
        }
        return itemVo;
    }

    @Override
    public CartVo getCartList(UserInfoTo userInfoTo) {
        //先将临时用户的购物车获取
        List<CartItemVo> cartItemList = getCartItemListByKey(CART_PREFIX + userInfoTo.getUserKey());
        if (userInfoTo.getUserId() != null) {
            //登录状态，需要把之前临时用户添加的购物项合并 然后将临时的删除
            BoundHashOperations<String, Object, Object> cartOps = getCartOps();
                for (CartItemVo itemVo : cartItemList) {
                    if (cartOps.hasKey(itemVo.getSkuId().toString())){
                        String str = (String) cartOps.get(itemVo.getSkuId().toString());
                        CartItemVo item = JSON.parseObject(str, CartItemVo.class);
                        item.setCount(item.getCount() + itemVo.getCount());
                        item.setPrice(item.getPrice().add(itemVo.getPrice()));
                        cartOps.put(item.toString(),JSON.toJSONString(item));
                    }else {
                        cartOps.put(itemVo.getSkuId().toString(),JSON.toJSONString(itemVo));
                    }
                }
                stringRedisTemplate.delete(CART_PREFIX + userInfoTo.getUserKey());
                List<CartItemVo> cartItemListByKey = getCartItemListByKey(CART_PREFIX + userInfoTo.getUserId());
                cartItemList.addAll(cartItemListByKey);
//            }
        }
        CartVo cart = new CartVo();

        BigDecimal totalPrice = new BigDecimal("0");

        for (CartItemVo itemVo : cartItemList) {
            //TODO 查询每个购物项的最新信息，并更新，应该交给消息队列去做，当有信息发生改变时，再去修改，而不是用户每次查询购物车就去更新
            //结算的时候需要，因为结算肯定要保证金额是最新的，需要来查询，而更改购物车就交给消息队列
            R info = productFeignService.info(itemVo.getSkuId());
            if (info.getCode() == 0){
                SkuInfoVo data = info.getData(new TypeReference<SkuInfoVo>() {
                });
                itemVo.setPrice(data.getPrice());
            }
            totalPrice = totalPrice.add(itemVo.getTotalPrice());
        }
        cart.setItems(cartItemList);
//        cart.setTotalCount();
        cart.setTotalPrice(totalPrice);
//        cart.setTotalType();
        return cart;

    }

    @Override
    public List<CartItemVo> getMemberCart() {
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        CartVo cartList = getCartList(userInfoTo);
        List<CartItemVo> items = cartList.getItems();
        return items;
    }

    private List<CartItemVo> getCartItemListByKey(String key) {
        BoundHashOperations<String, Object, Object> hashOps = stringRedisTemplate.boundHashOps(key);
        List<Object> values = hashOps.values();
        List<CartItemVo> collect = values.stream().map((obj) -> {
            String string = (String) obj;
            return JSON.parseObject(string,CartItemVo.class);
        }).collect(Collectors.toList());
        return collect;
    }

    /**
     * 获取到我们要操作的购物车
     *
     * @return
     */
    public BoundHashOperations<String, Object, Object> getCartOps() {
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        String pre = CART_PREFIX;
        if (userInfoTo.getUserId() == null) {
            pre += userInfoTo.getUserKey();
        } else {
            pre += userInfoTo.getUserId();
        }

        BoundHashOperations<String, Object, Object> operations = stringRedisTemplate.boundHashOps(pre);
        return operations;
    }
}
